# -*- coding: utf-8 -*-
# @Time    : 2024/6/26 14:34
# @Author  : yujiahao
# @File    : 15_pandas_obj.py
# @description:Python Pandas分类对象

'''

通常情况下，数据集中会存在许多同一类别的信息，比如相同国家、相同行政编码、相同性别等，当这些相同类别的数据多次出现时，就会给数据处理增添许多麻烦，导致数据集变得臃肿，不能直观、清晰地展示数据。

针对上述问题，Pandas 提供了分类对象（Categorical Object），该对象能够实现有序排列、自动去重的功能，但是它不能执行运算。

'''
import numpy as np
import pandas as pd


# todo 1、对象创建
def creat_obj():
    # 1) 指定dtype创建
    '''
    虽然传递给 Series 四个元素值，但是它的类别为 3，这是因为 a 的类别存在重复。
    运行结果：
    0    a
    1    b
    2    c
    3    a
    dtype: category
Categories (3, object): ['a', 'b', 'c']

    '''
    s = pd.Series(["a", "b", "c", "a"], dtype="category")
    print('指定dtype创建\n', s)

    print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')

    # 2) pd.Categorical

    '''
    通过 Category  的构造函数，您可以创建一个类别对象。构造函数，如下所示：
        pandas.Categorical(values, categories, ordered)
        
        values：以列表的形式传参，表示要分类的值。
        ordered：布尔值，默认为 False，若为 Ture，表示对分类的数据进行排序。
        dtype：返回一个 category 类型，表示分类对象。
    
    '''

    # 第二个参数值表示类别，当列表中不存在某一类别时，会自动将类别值设置为NA。比如第一个里面的d
    cat = pd.Categorical(['a', 'b', 'c', 'a', 'b', 'c', 'd'], ['c', 'b', 'a'])
    print(cat)

    print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')

    # 通过指定ordered = True来实现有序分类。
    cat = pd.Categorical(['a', 'b', 'c', 'a', 'b', 'c', 'd'], ['c', 'b', 'a'], ordered=True)

    print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')

    print(cat)

    print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')

    # 求最小值
    print(cat.min())


# todo 2、获取信息
def get_data():
    # 获取统计信息
    '''对已经分类的数据使用 describe() 方法，就会得到和数据统计相关的摘要信息。'''
    cat = pd.Categorical(["a", "c", "c", np.nan], categories=["b", "a", "c"])
    df = pd.DataFrame({"cat": cat, "s": ["a", "c", "c", np.nan]})

    print(df.describe())

    print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')

    print(df["cat"].describe())


#  todo 3、重命名类别


def pandas_rename_class():
    # 要想对类别实现重命名，可以通过 Series.cat.rename_categories来实现的

    s = pd.Series(["a", "b", "c", "a"], dtype="category")

    # 使用 rename_categories 方法对类名重命名
    '''
    1、s.cat.categories 返回当前的类别列表。
    2、使用列表推导式 ["Group %s" % g for g in s.cat.categories] 创建新的类别名称列表，例如 ['Group a', 'Group b', 'Group c']。
    3、s.cat.rename_categories(new_categories) 返回一个新的 Series，其中类别被重命名为新的类别名称。
    
    
    
    转换为分类数据类型: 在对 Series 进行分类操作之前，必须先将其转换为分类数据类型。
    使用 .cat 访问器: 只有分类数据类型的 Series 才能使用 .cat 访问器和相关方法，如 rename_categories。
    下面这个就会报错，必须将Series装换为分类数据类型
    s = pd.Series(["a", "b", "c", "a"])
    增加这个，不会报错    s = s.astype("category")

    '''
    s = s.cat.rename_categories(["Group %s" % g for g in s.cat.categories])
    print(s.cat.categories)


# todo 4、追加新类别
def pandas_append():
    # 使用 s.cat.add_categories() 方法，可以追加新类别。
    s = pd.Series(["a", "b", "c", "a"], dtype="category")
    # 追加新类别
    s = s.cat.add_categories([5])
    # 查看现有类别
    print(s.cat.categories)


# todo 5、删除类别
def pandas_del():
    '''使用 remove_categories() 方法，可以删除不需要的类别'''
    s = pd.Series(["a", "b", "c", "a"], dtype="category")
    # 原序列
    print(s)

    print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')

    # 删除后序列
    print(s.cat.remove_categories("a"))


# todo 5、分类对象比较
def pandas_compare():
    '''在下述两种情况下，我们可以对分类对象进行比较：
            当两个类别对象长度相同时，可以进行比较运算；
            当两个类别的 ordered 均等于 True，并且类别相同时，可以进行比较运算，比如 ==，！=，>，>=，< 和 <=。
    '''

    s1 = ['a', 'a', 'b', 'd', 'c']
    # 当满足两个类别长度相同时
    ss0 = pd.Categorical(s1, categories=['a', 'd', 'b', 'c'])
    ss1 = pd.Categorical(s1)
    print(ss0 == ss1)

    print('''\n-----------------------------------☆☆☆分割线☆☆☆----------------------------------------\n''')

    s1 = ['a', 'a', 'b', 'd', 'c']
    s2 = ['a', 'b', 'b', 'd', 'c']
    # 满足上述第二个条件，类别相同，并且ordered均为True
    ss0 = pd.Categorical(s1, categories=['a', 'd', 'b', 'c'], ordered=True)
    ss1 = pd.Categorical(s2, categories=['a', 'd', 'b', 'c'], ordered=True)
    print(ss0 < ss1)


def main():
    # creat_obj()
    # get_data()
    # pandas_rename_class()
    # pandas_append()
    # pandas_del()
    pandas_compare()


if __name__ == '__main__':
    main()
